using System;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using SecretLabs.NETMF.Hardware.Netduino;
using System.Threading;

namespace TFT_SPI_DisplayModule
{
    public class TFT01 : ILI9341_API
    {
        public const ushort RED = 0xf800;
        public const ushort BLACK = 0x0000;
        public const ushort WHITE = 0xffff;
        static Cpu.Pin LCD_WR = Pins.GPIO_PIN_D13;
        static Cpu.Pin LCD_RS = Pins.GPIO_PIN_D11;
        static Cpu.Pin LCD_DC = Pins.GPIO_PIN_A2;
        static Cpu.Pin LCD_RESET = Pins.GPIO_PIN_A1;
        static Cpu.Pin LCD_CS = Pins.GPIO_PIN_D10;
        SPI.Configuration Device1;
        SPI SPIBus;
        int Width, Height;
        const byte FONT_X = 8, FONT_Y = 8, FONT_SPACE = 6;
        bool UseSPI = true;
        static bool OrientationIsLandscape = true;
        const bool MemoryAccessControlNormalOrder = false, MemoryAccessControlReverseOrder = true;
        const bool MemoryAccessControlColorOrderBGR = false, MemoryAccessControlColorOrderRGB = true;
        OutputPort P_SCK;
        OutputPort P_MOSI;
        OutputPort P_DC;
        OutputPort P_RESET;
        OutputPort P_CS;

        static byte lcdPortraitConfig = lcdBuildMemoryAccessControlConfig(
                                                    MemoryAccessControlNormalOrder, // rowAddressOrder
                                                    MemoryAccessControlReverseOrder, // columnAddressOrder
                                                    MemoryAccessControlNormalOrder, // rowColumnExchange
                                                    MemoryAccessControlNormalOrder, // verticalRefreshOrder
                                                    MemoryAccessControlColorOrderRGB, // colorOrder
                                                    MemoryAccessControlNormalOrder); // horizontalRefreshOrder

        static byte lcdLandscapeConfig = lcdBuildMemoryAccessControlConfig(
                                                          MemoryAccessControlNormalOrder, // rowAddressOrder
                                                          MemoryAccessControlNormalOrder, // columnAddressOrder
                                                          MemoryAccessControlReverseOrder, // rowColumnExchange
                                                          MemoryAccessControlReverseOrder, // verticalRefreshOrder
                                                          MemoryAccessControlColorOrderRGB, // colorOrder
                                                          MemoryAccessControlReverseOrder); // horizontalRefreshOrder
        static byte lcdBuildMemoryAccessControlConfig(
                        bool rowAddressOrder,
                        bool columnAddressOrder,
                        bool rowColumnExchange,
                        bool verticalRefreshOrder,
                        bool colorOrder,
                        bool horizontalRefreshOrder)
        {
            byte value = 0;
            if (horizontalRefreshOrder) value |= 0x0004;
            if (colorOrder) value |= 0x0008;
            if (verticalRefreshOrder) value |= 0x0010;
            if (rowColumnExchange) value |= 0x0020;
            if (columnAddressOrder) value |= 0x0040;
            if (rowAddressOrder) value |= 0x0080;
            return value;
        }
        public TFT01(bool UseSPI, bool IsLandscape)
        {
            this.UseSPI = UseSPI;

            if (UseSPI)
            {
                Device1 = new SPI.Configuration(
       Pins.GPIO_PIN_D10, // CS-pin
       false,             // CS-pin active state
       0,                 // The setup time for the SS port
        0,                 // The hold time for the SS port
       false,              // The idle state of the clock
       true,             // The sampling clock edge
       1311,              // The SPI clock rate in KHz
        SPI_Devices.SPI1   // The used SPI bus (refers to a MOSI MISO and SCLK pinset)
   );
                SPIBus = new SPI(Device1);
                P_RESET = new OutputPort(LCD_RESET, false);
                P_DC = new OutputPort(LCD_DC, false);
            }
            else
            {
                P_SCK = new OutputPort(LCD_WR, false);
                P_MOSI = new OutputPort(LCD_RS, false);
                P_RESET = new OutputPort(LCD_RESET, false);
                P_CS = new OutputPort(LCD_CS, false);
                P_DC = new OutputPort(LCD_DC, false);
            }
            LCD_Init();
            SetOrientation(IsLandscape);
        }

        void LCD_Write_Bus(byte[] data)
        {
            if (UseSPI)
            {
                SPIBus.Write(data);
            }
            else
            {
                P_CS.Write(false);
                for (int a = 0; a < data.Length; a++)
                {
                    byte b = data[a];
                    for (int c = 0; c < 8; c++)
                    {
                        P_MOSI.Write((b & 0x80) != 0);
                        b = (byte)(b << 1);
                        P_SCK.Write(false);
                        P_SCK.Write(true);
                    }
                }
                P_CS.Write(true);
            }
        }
        void LCD_Write_Bus(ushort[] data)
        {
            if (UseSPI)
            {
                SPIBus.Write(data);
            }
            else
            {
                for (int a = 0; a < data.Length; a++)
                {
                    foreach (ushort word in data)
                    {
                        LCD_Write_Bus(new byte[] { (byte)(word >> 8), (byte)word });
                    }
                }
            }
        }
        void LCD_Write_COMMAND(byte VL)
        {
            P_DC.Write(false);
            LCD_Write_Bus(new[] { VL });
        }

        void LCD_Write_DATA(byte VL)
        {
            P_DC.Write(true);
            LCD_Write_Bus(new[] { VL });
        }
        void LCD_Write_DATA(byte[] bytes)
        {
            P_DC.Write(true);
            LCD_Write_Bus(bytes);
        }
        void LCD_Write_DATA(ushort[] words)
        {
            P_DC.Write(true);
            LCD_Write_Bus(words);
        }
        static byte[][] _initializationData = {
new byte[]{0xcf},new byte[]{0x00,0x83,0x30},
new byte[]{0xed},new byte[]{0x64,0x03,0x12,0x81},
new byte[]{0xe8},new byte[]{0x85,0x01,0x79},
new byte[]{0xcb},new byte[]{0x39,0x2c,0x00,0x34,0x02},
new byte[]{0xf7},new byte[]{0x20},
new byte[]{0xea},new byte[]{0x00,0x00},

new byte[]{cmd_PowerControl1},new byte[]{0x26},//VRH [5:0]: Set the GVDD level, which is a reference level for the VCOM level and the grayscale voltage level. 
new byte[]{cmd_PowerControl2},new byte[]{0x11},//BT [2:0]: Sets the factor used in the step-up circuits.
new byte[]{cmd_VCOM_Control_1},new byte[]{0x35,0x3e},//VMH [6:0] : Set the VCOMH voltage. 4.25V/-1.5
new byte[]{cmd_VCOM_Control_2},new byte[]{0xbe},//VMF [6:0]: Set the VCOM offset voltage. 
new byte[]{cmd_MemoryAccessControl},new byte[]{lcdPortraitConfig},
new byte[]{cmd_PixelFormat},new byte[]{0x55},//16-bits per pixel
new byte[]{cmd_FrameControlNormal},new byte[]{0x00,0x1b},
//new byte[]{cmd_DisplayFunctionControl},new byte[]{0x08,0x82,0x27},
new byte[]{0xf2},new byte[]{0x08},
new byte[]{cmd_GammaSet},new byte[]{0x01},
new byte[]{cmd_Positive_Gamma_Correction},new byte[]{0x1f,0x1a,0x18,0x0a,0x0f,0x06,0x45,0x87,0x32,0x0a,0x07,0x02,0x07,0x05,0x00},
new byte[]{cmd_Negative_Gamma_Correction},new byte[]{0x00,0x25,0x27,0x05,0x10,0x09,0x3a,0x78,0x4d,0x05,0x18,0x0d,0x38,0x3a,0x1f},
  
                                              };
        void LCD_Init()
        {
            P_RESET.Write(false);
            Thread.Sleep(10);
            P_RESET.Write(true);
            LCD_Write_COMMAND(cmd_SoftwareReset);
            LCD_Write_COMMAND(cmd_DisplayOff);

            for (int i = 0; i < _initializationData.Length; i += 2)
            {
                LCD_Write_COMMAND(_initializationData[i][0]);

                LCD_Write_DATA(_initializationData[i + 1]);
            }

            LCD_Write_COMMAND(0x2a);
            LCD_Write_DATA(0x00);
            LCD_Write_DATA(0x00);
            LCD_Write_DATA(0x00);
            LCD_Write_DATA(0xEF);

            LCD_Write_COMMAND(0x2b);
            LCD_Write_DATA(0x00);
            LCD_Write_DATA(0x00);
            LCD_Write_DATA(0x01);
            LCD_Write_DATA(0x3F);

            LCD_Write_COMMAND(cmd_EntryModeSet);
            LCD_Write_DATA(0x07);

            LCD_Write_COMMAND(cmd_DisplayFunctionControl);
            LCD_Write_DATA(new byte[] { 0x0a, 0x82, 0x27, 0x00 });

            LCD_Write_COMMAND(cmd_ExitSleep);    //Exit Sleep 
            Thread.Sleep(120);

            LCD_Write_COMMAND(cmd_DisplayOn);    //Display on 
            Thread.Sleep(100);
            LCD_Write_COMMAND(cmd_MemoryWrite);
        }
        public void SetCol(int StartCol, int EndCol)
        {
            LCD_Write_COMMAND(cmd_ColumnAddressSet);
            LCD_Write_DATA(new[] { (ushort)StartCol, (ushort)EndCol });
        }
        public void SetPage(int StartPage, int EndPage)
        {
            LCD_Write_COMMAND(cmd_PageAddressSet);
            LCD_Write_DATA(new[] { (ushort)StartPage, (ushort)EndPage });
        }
        public void FillScreen(ushort Left, ushort Right, ushort Top, ushort Bottom, ushort color)
        {
            int i = 0;

            int Width = Right - Left + 1;
            int Height = Bottom - Top + 1;
            SetCol(Left, Right);
            SetPage(Top, Bottom);
            //SetCol(Top, Bottom);
            //SetPage((ushort)(319 - Left - Width), (ushort)(319 - Left));
            LCD_Write_COMMAND(cmd_MemoryWrite);/* start to write to display ram */

            P_DC.Write(true);

            ushort[] t = new ushort[Height];
            for (i = 0; i < Height; i++)
            {
                t[i] = color;
            }
            int size = Width * Height;
            for (i = 0; i < size; i += Height)
            {
                LCD_Write_Bus(t);
            }
        }

        public void ClearScreen()
        {
            SetWindow(0, Width - 1, 0, Height - 1);
            ushort[] b = new ushort[Width];
            Array.Clear(b, 0, Width);
            LCD_Write_COMMAND(cmd_MemoryWrite);
            P_DC.Write(true);
            for (int y = 0; y < Height; y++)
            {
                LCD_Write_Bus(b);
            }
        }
        public void DrawHorizontalLine(ushort x, ushort y, ushort length, ushort color)
        {
            SetWindow(x, x + length, y, y);
            LCD_Write_COMMAND(cmd_MemoryWrite);
            ushort[] b = new ushort[length];
            for (int i = 0; i < length; i++) b[i] = color;

            P_DC.Write(true);
            LCD_Write_Bus(b);
        }
        public void DrawVerticalLine(int x, int y, int length, int color)
        {
            for (int line = y; line <= y + length; line++)
            {
                SetPixel(x, line, color);
            }
        }
        public void SetPixel(int x, int y, int color)
        {
            SetWindow(x, x, y, y);
            //LCD_Write_COMMAND(cmd_MemoryWrite);
            LCD_Write_DATA(new[] { (ushort)color });
        }
        int Abs(int x) { if (x > 0)return x; else return -x; }
        public void drawLine(int x0, int y0, int x1, int y1, int color)
        {

            int x = x1 - x0;
            int y = y1 - y0;
            int dx = Abs(x), sx = x0 < x1 ? 1 : -1;
            int dy = -Abs(y), sy = y0 < y1 ? 1 : -1;
            int err = dx + dy, e2;                                                /* error value e_xy             */
            for (; ; )
            {                                                           /* loop                         */
                SetPixel(x0, y0, color);
                e2 = 2 * err;
                if (e2 >= dy)
                {                                                 /* e_xy+e_x > 0                 */
                    if (x0 == x1) break;
                    err += dy; x0 += sx;
                }
                if (e2 <= dx)
                {                                                 /* e_xy+e_y < 0                 */
                    if (y0 == y1) break;
                    err += dx; y0 += sy;
                }
            }
        }
        void SetWindow(int x0, int y0, int x1, int y1)
        {
            LCD_Write_COMMAND(cmd_ColumnAddressSet);
            LCD_Write_DATA((byte)((x0 >> 8) & 0xFF));
            LCD_Write_DATA((byte)(x0 & 0xFF));
            LCD_Write_DATA((byte)((y0 >> 8) & 0xFF));
            LCD_Write_DATA((byte)(y0 & 0xFF));
            LCD_Write_COMMAND(cmd_PageAddressSet);
            LCD_Write_DATA((byte)((x1 >> 8) & 0xFF));
            LCD_Write_DATA((byte)(x1 & 0xFF));
            LCD_Write_DATA((byte)((y1 >> 8) & 0xFF));
            LCD_Write_DATA((byte)(y1 & 0xFF));
            LCD_Write_COMMAND(cmd_MemoryWrite);

            //            SetCol(x0, y0);
            //SetPage(x1, y1);
            //LCD_Write_COMMAND(cmd_MemoryWrite);
        }
        public void SetOrientation(bool isLandscape)
        {
            OrientationIsLandscape = isLandscape;
            LCD_Write_COMMAND(cmd_MemoryAccessControl);
            if (isLandscape)
            {
                LCD_Write_DATA(lcdPortraitConfig);
                Width = 240;
                Height = 320;
            }
            else
            {
                LCD_Write_DATA(lcdLandscapeConfig);
                Width = 320;
                Height = 240;
            }
            LCD_Write_COMMAND(cmd_MemoryWrite);
            SetWindow(0, Width - 1, 0, Height - 1);
        }
        public ushort ColorFromRgb(byte r,byte g,byte b)
    {
        return (ushort)((r<< 11) | (g<< 5) | b);
    }
        public void DrawChar(int x, int y, int c, int color)
        {
            ushort[] pixels = new ushort[8];
            SetWindow(x, x + 8, y,y);
            byte[] scanLines = font8x8_basic[c];
            foreach(byte data in scanLines)
            {
                SetWindow(x, x + 8, y, y);
                pixels[0] = (data & 0x80) != 0 ? (ushort)color : (ushort)0;
                pixels[1] = (data & 0x40) != 0 ? (ushort)color : (ushort)0;
                pixels[2] = (data & 0x20) != 0 ? (ushort)color : (ushort)0;
                pixels[3] = (data & 0x10) != 0 ? (ushort)color : (ushort)0;
                pixels[4] = (data & 0x8) != 0 ? (ushort)color : (ushort)0;
                pixels[5] = (data & 0x4) != 0 ? (ushort)color : (ushort)0;
                pixels[6] = (data & 0x2) != 0 ? (ushort)color : (ushort)0;
                pixels[7] = (data & 0x1) != 0 ? (ushort)color : (ushort)0;

                LCD_Write_DATA(pixels);
                y++;
            }
        }
        public void DrawString(int x, int y, string s, int color)
        {
            foreach (char c in s)
            {
                DrawChar(x, y, (int)c, color);
                x += 8;
            }
        }
        static byte[][] font8x8_basic = {
    new byte[]{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0000 (nul)
    new byte[]{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0001
    new byte[]{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0002
    new byte[]{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0003
    new byte[]{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0004
    new byte[]{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0005
    new byte[]{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0006
    new byte[]{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0007
   new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0008
   new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0009
   new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+000A
   new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+000B
   new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+000C
   new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+000D
   new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+000E
   new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+000F
   new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0010
   new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0011
   new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0012
   new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0013
   new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0014
   new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0015
   new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0016
   new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0017
   new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0018
   new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0019
   new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+001A
   new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+001B
   new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+001C
   new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+001D
   new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+001E
   new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+001F
   new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0020 (space)
   new byte[] { 0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00},   // U+0021 (!)
   new byte[] { 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0022 (")
   new byte[] { 0x36, 0x36, 0x7F, 0x36, 0x7F, 0x36, 0x36, 0x00},   // U+0023 (#)
   new byte[] { 0x0C, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x0C, 0x00},   // U+0024 ($)
   new byte[] { 0x00, 0x63, 0x33, 0x18, 0x0C, 0x66, 0x63, 0x00},   // U+0025 (%)
   new byte[] { 0x1C, 0x36, 0x1C, 0x6E, 0x3B, 0x33, 0x6E, 0x00},   // U+0026 (&)
   new byte[] { 0x06, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0027 (')
   new byte[] { 0x18, 0x0C, 0x06, 0x06, 0x06, 0x0C, 0x18, 0x00},   // U+0028 (()
   new byte[] { 0x06, 0x0C, 0x18, 0x18, 0x18, 0x0C, 0x06, 0x00},   // U+0029 ())
   new byte[] { 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00},   // U+002A (*)
   new byte[] { 0x00, 0x0C, 0x0C, 0x3F, 0x0C, 0x0C, 0x00, 0x00},   // U+002B (+)
   new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x06},   // U+002C (,)
   new byte[] { 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00},   // U+002D (-)
   new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00},   // U+002E (.)
   new byte[] { 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00},   // U+002F (/)
   new byte[] { 0x3E, 0x63, 0x73, 0x7B, 0x6F, 0x67, 0x3E, 0x00},   // U+0030 (0)
   new byte[] { 0x0C, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x3F, 0x00},   // U+0031 (1)
   new byte[] { 0x1E, 0x33, 0x30, 0x1C, 0x06, 0x33, 0x3F, 0x00},   // U+0032 (2)
   new byte[] { 0x1E, 0x33, 0x30, 0x1C, 0x30, 0x33, 0x1E, 0x00},   // U+0033 (3)
   new byte[] { 0x38, 0x3C, 0x36, 0x33, 0x7F, 0x30, 0x78, 0x00},   // U+0034 (4)
   new byte[] { 0x3F, 0x03, 0x1F, 0x30, 0x30, 0x33, 0x1E, 0x00},   // U+0035 (5)
   new byte[] { 0x1C, 0x06, 0x03, 0x1F, 0x33, 0x33, 0x1E, 0x00},   // U+0036 (6)
   new byte[] { 0x3F, 0x33, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x00},   // U+0037 (7)
   new byte[] { 0x1E, 0x33, 0x33, 0x1E, 0x33, 0x33, 0x1E, 0x00},   // U+0038 (8)
   new byte[] { 0x1E, 0x33, 0x33, 0x3E, 0x30, 0x18, 0x0E, 0x00},   // U+0039 (9)
   new byte[] { 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x00},   // U+003A (:)
   new byte[] { 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x06},   // U+003B (//)
   new byte[] { 0x18, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x18, 0x00},   // U+003C (<)
   new byte[] { 0x00, 0x00, 0x3F, 0x00, 0x00, 0x3F, 0x00, 0x00},   // U+003D (=)
   new byte[] { 0x06, 0x0C, 0x18, 0x30, 0x18, 0x0C, 0x06, 0x00},   // U+003E (>)
   new byte[] { 0x1E, 0x33, 0x30, 0x18, 0x0C, 0x00, 0x0C, 0x00},   // U+003F (?)
   new byte[] { 0x3E, 0x63, 0x7B, 0x7B, 0x7B, 0x03, 0x1E, 0x00},   // U+0040 (@)
   new byte[] { 0x0C, 0x1E, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x00},   // U+0041 (A)
   new byte[] { 0x3F, 0x66, 0x66, 0x3E, 0x66, 0x66, 0x3F, 0x00},   // U+0042 (B)
   new byte[] { 0x3C, 0x66, 0x03, 0x03, 0x03, 0x66, 0x3C, 0x00},   // U+0043 (C)
   new byte[] { 0x1F, 0x36, 0x66, 0x66, 0x66, 0x36, 0x1F, 0x00},   // U+0044 (D)
   new byte[] { 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x46, 0x7F, 0x00},   // U+0045 (E)
   new byte[] { 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x06, 0x0F, 0x00},   // U+0046 (F)
   new byte[] { 0x3C, 0x66, 0x03, 0x03, 0x73, 0x66, 0x7C, 0x00},   // U+0047 (G)
   new byte[] { 0x33, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x33, 0x00},   // U+0048 (H)
   new byte[] { 0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00},   // U+0049 (I)
   new byte[] { 0x78, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E, 0x00},   // U+004A (J)
   new byte[] { 0x67, 0x66, 0x36, 0x1E, 0x36, 0x66, 0x67, 0x00},   // U+004B (K)
   new byte[] { 0x0F, 0x06, 0x06, 0x06, 0x46, 0x66, 0x7F, 0x00},   // U+004C (L)
   new byte[] { 0x63, 0x77, 0x7F, 0x7F, 0x6B, 0x63, 0x63, 0x00},   // U+004D (M)
   new byte[] { 0x63, 0x67, 0x6F, 0x7B, 0x73, 0x63, 0x63, 0x00},   // U+004E (N)
   new byte[] { 0x1C, 0x36, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00},   // U+004F (O)
   new byte[] { 0x3F, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x0F, 0x00},   // U+0050 (P)
   new byte[] { 0x1E, 0x33, 0x33, 0x33, 0x3B, 0x1E, 0x38, 0x00},   // U+0051 (Q)
   new byte[] { 0x3F, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x67, 0x00},   // U+0052 (R)
   new byte[] { 0x1E, 0x33, 0x07, 0x0E, 0x38, 0x33, 0x1E, 0x00},   // U+0053 (S)
   new byte[] { 0x3F, 0x2D, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00},   // U+0054 (T)
   new byte[] { 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0x00},   // U+0055 (U)
   new byte[] { 0x33, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00},   // U+0056 (V)
   new byte[] { 0x63, 0x63, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0x00},   // U+0057 (W)
   new byte[] { 0x63, 0x63, 0x36, 0x1C, 0x1C, 0x36, 0x63, 0x00},   // U+0058 (X)
   new byte[] { 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x0C, 0x1E, 0x00},   // U+0059 (Y)
   new byte[] { 0x7F, 0x63, 0x31, 0x18, 0x4C, 0x66, 0x7F, 0x00},   // U+005A (Z)
   new byte[] { 0x1E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x1E, 0x00},   // U+005B ([)
   new byte[] { 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00},   // U+005C (\)
   new byte[] { 0x1E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1E, 0x00},   // U+005D (])
   new byte[] { 0x08, 0x1C, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00},   // U+005E (^)
   new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF},   // U+005F (_)
   new byte[] { 0x0C, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0060 (`)
   new byte[] { 0x00, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x6E, 0x00},   // U+0061 (a)
   new byte[] { 0x07, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3B, 0x00},   // U+0062 (b)
   new byte[] { 0x00, 0x00, 0x1E, 0x33, 0x03, 0x33, 0x1E, 0x00},   // U+0063 (c)
   new byte[] { 0x38, 0x30, 0x30, 0x3e, 0x33, 0x33, 0x6E, 0x00},   // U+0064 (d)
   new byte[] { 0x00, 0x00, 0x1E, 0x33, 0x3f, 0x03, 0x1E, 0x00},   // U+0065 (e)
   new byte[] { 0x1C, 0x36, 0x06, 0x0f, 0x06, 0x06, 0x0F, 0x00},   // U+0066 (f)
   new byte[] { 0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x1F},   // U+0067 (g)
   new byte[] { 0x07, 0x06, 0x36, 0x6E, 0x66, 0x66, 0x67, 0x00},   // U+0068 (h)
   new byte[] { 0x0C, 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00},   // U+0069 (i)
   new byte[] { 0x30, 0x00, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E},   // U+006A (j)
   new byte[] { 0x07, 0x06, 0x66, 0x36, 0x1E, 0x36, 0x67, 0x00},   // U+006B (k)
   new byte[] { 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00},   // U+006C (l)
   new byte[] { 0x00, 0x00, 0x33, 0x7F, 0x7F, 0x6B, 0x63, 0x00},   // U+006D (m)
   new byte[] { 0x00, 0x00, 0x1F, 0x33, 0x33, 0x33, 0x33, 0x00},   // U+006E (n)
   new byte[] { 0x00, 0x00, 0x1E, 0x33, 0x33, 0x33, 0x1E, 0x00},   // U+006F (o)
   new byte[] { 0x00, 0x00, 0x3B, 0x66, 0x66, 0x3E, 0x06, 0x0F},   // U+0070 (p)
   new byte[] { 0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x78},   // U+0071 (q)
   new byte[] { 0x00, 0x00, 0x3B, 0x6E, 0x66, 0x06, 0x0F, 0x00},   // U+0072 (r)
   new byte[] { 0x00, 0x00, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x00},   // U+0073 (s)
   new byte[] { 0x08, 0x0C, 0x3E, 0x0C, 0x0C, 0x2C, 0x18, 0x00},   // U+0074 (t)
   new byte[] { 0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x6E, 0x00},   // U+0075 (u)
   new byte[] { 0x00, 0x00, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00},   // U+0076 (v)
   new byte[] { 0x00, 0x00, 0x63, 0x6B, 0x7F, 0x7F, 0x36, 0x00},   // U+0077 (w)
   new byte[] { 0x00, 0x00, 0x63, 0x36, 0x1C, 0x36, 0x63, 0x00},   // U+0078 (x)
   new byte[] { 0x00, 0x00, 0x33, 0x33, 0x33, 0x3E, 0x30, 0x1F},   // U+0079 (y)
   new byte[] { 0x00, 0x00, 0x3F, 0x19, 0x0C, 0x26, 0x3F, 0x00},   // U+007A (z)
   new byte[] { 0x38, 0x0C, 0x0C, 0x07, 0x0C, 0x0C, 0x38, 0x00},   // U+007B ({)
   new byte[] { 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00},   // U+007C (|)
   new byte[] { 0x07, 0x0C, 0x0C, 0x38, 0x0C, 0x0C, 0x07, 0x00},   // U+007D (})
   new byte[] { 0x6E, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+007E (~)
   new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}    // U+007F
};
    }
}
